#pragma once

#include <iostream>
#include <queue>
#include <mutex>
#include <pthread.h>
#include "lockGuard.hpp"

// #define INI_MTX(mtx) pthread_mutex_init(&mtx, nullptr)
// #define INI_COND(cond) pthread_cond_init(&_Empty, nullptr);
// #define INI_COND(cond) pthread_cond_init(&_Full, nullptr);

const int g_DefaultCap = 5;

template <class T>
class BlockQueue
{
private:
    bool isQueueEmpty()
    {
        return _bq.size() == 0;
    }

    bool isQueueFull()
    {
        return _bq.size() == _capacity;
    }

public:
    BlockQueue(int capacity = g_DefaultCap)
        : _capacity(capacity)
    {
        pthread_mutex_init(&_mtx, nullptr);

        pthread_cond_init(&_Empty, nullptr);
        pthread_cond_init(&_Full, nullptr);
    }

    void push(const T &in)
    {
        lockGuard lockguard(&_mtx); // 自动调用构造函数申请锁

        while (isQueueFull()) // 用while而非if==>访问临界资源100%确定资源就绪
            pthread_cond_wait(&_Full, &_mtx);

        _bq.push(in);

        pthread_cond_signal(&_Empty);
    } // 自动调用lockguard析构函数解锁

    void pop(T *out)
    {
        lockGuard lockguard(&_mtx);

        while (isQueueEmpty())
            pthread_cond_wait(&_Empty, &_mtx);

        *out = _bq.front();
        _bq.pop();

        pthread_cond_signal(&_Full);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_Empty);
        pthread_cond_destroy(&_Full);
    }

private:
    std::queue<T> _bq;     // 阻塞队列
    int _capacity;         // 队列容量
    pthread_mutex_t _mtx;  // 互斥锁
    pthread_cond_t _Empty; // 用它来表示bq 是否空的条件
    pthread_cond_t _Full;  // 用它来表示bq 是否满的条件
};
